using System;
using System.Collections.Generic;

namespace OracleInternal.I18N
{
	internal class UTF16ConvUtility
	{
		public delegate int ConvertToCharsDelegate<T>(byte[] bytes, int byteOffsets, int byteCounts, T[] chars, int charOffset, ref int charCount, bool bUseReplacementChar);

		public delegate int GetBytesOffsetDelegate(byte[] bytes, int byteOffset, int byteCount, ref int charCount);

		public delegate int GetCharsLengthDelegate(byte[] bytes, int byteOffset, int byteCount, ref int bytesCounted);

		private UTF16ConvUtility()
		{
		}

		public static bool IsHiSurrogate(char c)
		{
			return (ushort)(c & 0xFC00) == 55296;
		}

		public static bool IsLoSurrogate(char c)
		{
			return (ushort)(c & 0xFC00) == 56320;
		}

		public static bool Check80toBF(byte b)
		{
			return (b & 0xC0) == 128;
		}

		public static bool Check80to8F(byte b)
		{
			return (b & 0xF0) == 128;
		}

		public static bool Check80to9F(byte b)
		{
			return (b & 0xE0) == 128;
		}

		public static bool CheckA0toBF(byte b)
		{
			return (b & 0xE0) == 160;
		}

		public static bool Check90toBF(byte b)
		{
			if ((b & 0xC0) == 128)
			{
				return (b & 0x30) != 0;
			}
			return false;
		}

		public static char Conv3ByteUTFtoUTF16(byte c, byte c2, byte c3)
		{
			if ((c != 224 || !CheckA0toBF(c2) || !Check80toBF(c3)) && (c < 225 || c > 239 || !Check80toBF(c2) || !Check80toBF(c3)))
			{
				return '\ufffd';
			}
			return (char)((uint)(((c & 0xF) << 12) | ((c2 & 0x3F) << 6)) | (c3 & 0x3Fu));
		}

		public static bool isDefined(string str)
		{
			int length = str.Length;
			for (int i = 0; i < length; i++)
			{
				char c = str[i];
				if (c >= '\udc00' && c <= '\udfff')
				{
					return false;
				}
				if (c >= '\ud800' && c <= '\udbff')
				{
					if (i + 1 >= length)
					{
						return false;
					}
					char c2 = str[i + 1];
					if (c2 < '\udc00' || c2 > '\udfff')
					{
						return false;
					}
					i++;
				}
				else if (c == '\ufffe' || c == '\uffff')
				{
					return false;
				}
			}
			return true;
		}

		public static void GetRemainingBytes(int numBytesToRead, byte[] buffer1, int offset1, int buffer1Bytes, IList<ArraySegment<byte>> bytes, ref int currSegIndex, ref int continuationOffset, byte[] dstBuffer)
		{
			int num = 0;
			for (int i = offset1; i < offset1 + buffer1Bytes; i++)
			{
				dstBuffer[num++] = buffer1[i];
				numBytesToRead--;
			}
			while (numBytesToRead > 0)
			{
				byte[] array = bytes[currSegIndex + 1].Array;
				int count = bytes[currSegIndex + 1].Count;
				int offset2 = bytes[currSegIndex + 1].Offset;
				continuationOffset = 0;
				for (int j = offset2; j < offset2 + count; j++)
				{
					dstBuffer[num++] = array[j];
					numBytesToRead--;
					continuationOffset++;
					if (numBytesToRead <= 0)
					{
						break;
					}
				}
				if (numBytesToRead > 0)
				{
					currSegIndex++;
				}
			}
		}

		public static int ConvertArraySegListToCharsImpl<T>(IList<ArraySegment<byte>> bytes, int bytesOffset, int bytesCount, T[] chars, int charOffset, ref int charCount, bool bUseReplacementChar, ConvertToCharsDelegate<T> t)
		{
			int num = charOffset;
			int charCount2 = charCount;
			int num2 = 0;
			int num3 = 0;
			int continuationOffset = 0;
			byte[] array = null;
			int byteCounts = 0;
			int idx = 0;
			int offSet = bytes[0].Offset;
			bool flag = false;
			if (bytesOffset > 0)
			{
				GetSegementIndices(bytes, bytesOffset, ref idx, ref offSet);
			}
			for (int i = idx; i < bytes.Count; i++)
			{
				if (flag)
				{
					break;
				}
				if (charCount2 <= 0)
				{
					break;
				}
				int num4 = bytes[i].Offset + continuationOffset;
				int num5 = bytes[i].Count - continuationOffset;
				if (i == idx)
				{
					num4 = offSet + continuationOffset;
					num5 = bytes[i].Count - (offSet - bytes[i].Offset) - continuationOffset;
				}
				if (bytesCount - num3 <= num5)
				{
					num5 = bytesCount - num3;
					flag = true;
				}
				int num6 = t(bytes[i].Array, num4, num5, chars, num, ref charCount2, bUseReplacementChar);
				num3 += num6;
				num += charCount2;
				num2 += charCount2;
				charCount2 = charCount - num2;
				if (charCount2 > 0 && num6 < num5 && !flag && i < bytes.Count - 1)
				{
					if (array == null)
					{
						array = new byte[4];
					}
					byte[] array2 = bytes[i + 1].Array;
					int num7 = num4 + num6;
					byte b = bytes[i].Array[num7];
					int num8 = (b & 0xF0) / 16;
					int buffer1Bytes = num5 - num6;
					switch (num8)
					{
					case 12:
					case 13:
						array[0] = b;
						array[1] = array2[bytes[i + 1].Offset];
						continuationOffset = 1;
						byteCounts = 2;
						break;
					case 14:
						GetRemainingBytes(3, bytes[i].Array, num7, buffer1Bytes, bytes, ref i, ref continuationOffset, array);
						byteCounts = 3;
						break;
					case 15:
						GetRemainingBytes(4, bytes[i].Array, num7, buffer1Bytes, bytes, ref i, ref continuationOffset, array);
						byteCounts = 4;
						break;
					}
					num6 = t(array, 0, byteCounts, chars, num, ref charCount2, bUseReplacementChar);
					if (num6 == 0)
					{
						break;
					}
					num3 += num6;
					num += charCount2;
					num2 += charCount2;
					charCount2 = charCount - num2;
				}
				else
				{
					continuationOffset = 0;
				}
			}
			charCount = num2;
			return num3;
		}

		public static int GetBytesOffsetListSegs(IList<ArraySegment<byte>> bytes, int charCount, GetBytesOffsetDelegate t)
		{
			int charCount2 = charCount;
			int num = 0;
			int num2 = 0;
			int continuationOffset = 0;
			byte[] array = null;
			int byteCount = 0;
			for (int i = 0; i < bytes.Count; i++)
			{
				if (num >= charCount)
				{
					break;
				}
				int num3 = bytes[i].Offset + continuationOffset;
				int num4 = bytes[i].Count - continuationOffset;
				byte[] array2 = bytes[i].Array;
				int num5 = t(array2, num3, num4, ref charCount2);
				num2 += num5;
				num += charCount2;
				charCount2 = charCount - num;
				if (charCount2 > 0 && num5 < num4 && i < bytes.Count - 1)
				{
					if (array == null)
					{
						array = new byte[4];
					}
					byte[] array3 = bytes[i + 1].Array;
					int num6 = num3 + num5;
					byte b = array2[num6];
					int num7 = (b & 0xF0) / 16;
					int buffer1Bytes = num4 - num5;
					switch (num7)
					{
					case 12:
					case 13:
						array[0] = b;
						array[1] = array3[bytes[i + 1].Offset];
						continuationOffset = 1;
						byteCount = 2;
						break;
					case 14:
						GetRemainingBytes(3, array2, num6, buffer1Bytes, bytes, ref i, ref continuationOffset, array);
						byteCount = 3;
						break;
					case 15:
						GetRemainingBytes(4, array2, num6, buffer1Bytes, bytes, ref i, ref continuationOffset, array);
						byteCount = 4;
						break;
					}
					num5 = t(array, 0, byteCount, ref charCount2);
					num2 += num5;
					num += charCount2;
					charCount2 = charCount - num;
				}
				else
				{
					continuationOffset = 0;
				}
			}
			return num2;
		}

		public static int GetCharsLengthListSegs(IList<ArraySegment<byte>> bytes, int bytesOffset, int bytesCount, GetCharsLengthDelegate t)
		{
			int num = 0;
			int bytesCounted = 0;
			int num2 = 0;
			int continuationOffset = 0;
			byte[] array = null;
			int byteCount = 0;
			int idx = 0;
			int offSet = bytes[0].Offset;
			bool flag = false;
			if (bytesOffset > 0)
			{
				GetSegementIndices(bytes, bytesOffset, ref idx, ref offSet);
			}
			for (int i = idx; i < bytes.Count; i++)
			{
				if (flag)
				{
					break;
				}
				int num3 = bytes[i].Offset + continuationOffset;
				int num4 = bytes[i].Count - continuationOffset;
				if (i == idx)
				{
					num3 = offSet + continuationOffset;
					num4 = bytes[i].Count - (offSet - bytes[i].Offset) - continuationOffset;
				}
				if (bytesCount - num2 <= num4)
				{
					num4 = bytesCount - num2;
					flag = true;
				}
				int num5 = t(bytes[i].Array, num3, num4, ref bytesCounted);
				num += num5;
				num2 += bytesCounted;
				if (bytesCounted < num4 && !flag && i < bytes.Count - 1)
				{
					if (array == null)
					{
						array = new byte[4];
					}
					byte[] array2 = bytes[i + 1].Array;
					int num6 = num3 + bytesCounted;
					byte b = bytes[i].Array[num6];
					int num7 = (b & 0xF0) / 16;
					int buffer1Bytes = num4 - bytesCounted;
					switch (num7)
					{
					case 12:
					case 13:
						array[0] = b;
						array[1] = array2[bytes[i + 1].Offset];
						continuationOffset = 1;
						byteCount = 2;
						break;
					case 14:
						GetRemainingBytes(3, bytes[i].Array, num6, buffer1Bytes, bytes, ref i, ref continuationOffset, array);
						byteCount = 3;
						break;
					case 15:
						GetRemainingBytes(4, bytes[i].Array, num6, buffer1Bytes, bytes, ref i, ref continuationOffset, array);
						byteCount = 4;
						break;
					}
					num5 = t(array, 0, byteCount, ref bytesCounted);
					num += num5;
					num2 += bytesCounted;
				}
				else
				{
					continuationOffset = 0;
				}
			}
			return num;
		}

		public static void GetSegementIndices(IList<ArraySegment<byte>> segs, int offset, ref int idx1, ref int offSet1)
		{
			int num = 0;
			int num2 = 0;
			int i = 0;
			idx1 = 0;
			offSet1 = segs[0].Offset;
			if (offset < 0)
			{
				return;
			}
			for (; i < segs.Count; i++)
			{
				num += segs[i].Count;
				if (offset < num)
				{
					num2 = num - offset;
					idx1 = i;
					offSet1 = segs[i].Offset + segs[i].Count - num2;
					return;
				}
			}
			idx1 = segs.Count;
		}
	}
}
